package ws.performancetest.tests.thread;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * This class provides several ways to synchronize the access to a shared object.
 *
 * Is for experimental purposes only.
 *
 * @author Wilson Santos, 36228 <wilson.santos@ua.pt>
 */
public class Synchronization {

  /** Binary semaphore, one permit. */
  private Semaphore sem = new Semaphore(1);
  private ReentrantLock lock = new ReentrantLock();
  private ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();
  private Lock readLock = rwlock.readLock();
  private Lock writeLock = rwlock.writeLock();
  /** Enables/disables the writing of the thread id. */
  public static final boolean doLog = false;
  /** Log with the thread Ids .*/
  private List<String> list = new LinkedList<String>();

  /** Lock using synchronized method. */
  public synchronized void synchronizedMethod() {
    if (doLog) {
      list.add(Thread.currentThread().getName());
    }
  }

  /** Lock using synchronized block. */
  public void synchronizedBlock() {
    synchronized (this) {
      if (doLog) {
        list.add(Thread.currentThread().getName());
      }
    }
  }

  /** Lock using {@link Semaphore}. */
  public void semaphore() throws InterruptedException {
    sem.acquire();
    if(doLog) {
      list.add(Thread.currentThread().getName());
    }
    sem.release();
  }

  /** Lock using {@link ReentrantLock} .*/
  public void lock() {
    lock.lock();
    if (doLog) {
      list.add(Thread.currentThread().getName());
    }
    lock.unlock();
  }

  /** Lock using the read lock of {@link ReentrantReadWriteLock} .*/
  public void readLock() {
    readLock.lock();
    if (doLog) {
      list.add(Thread.currentThread().getName());
    }
    readLock.unlock();
  }

  /** Lock using the write lock of {@link ReentrantReadWriteLock} .*/
  public void writeLock() {
    writeLock.lock();
    if (doLog) {
      list.add(Thread.currentThread().getName());
    }
    writeLock.unlock();
  }

  /** Remove all registered thread information. */
  public void clearList() {
    list.clear();
  }

  @Override
  public String toString() {
    String ret = "";
    for (String s : list) {
      ret += s + "\n";
    }
    return ret;
  }
}
